#include "vec4.h"

#include "math.h"
#include "util/mmgr.h"		// Needs to come in early
#include "util/common_macros.h"		// Needs to come in early

using namespace math;
// Constructors

Vec4::Vec4(float _x,float _y,float _z, float _w): x(_x), y(_y), z(_z), w(_w)
{
}

Vec4::Vec4(): x(0), y(0), z(0), w(0)
{
}

Vec4::Vec4(float* _Vec) :x(_Vec[0]),y(_Vec[1]),z(_Vec[2]), w(_Vec[3])
{

}



Vec4& Vec4::operator = ( const Vec4& _Vec) 
{
	x = _Vec.x;
	y = _Vec.y;
	z = _Vec.z;
	w = _Vec.w;
	return *this;
}

void Vec4::Reset()
{
	x = y = z = w = 0.0f;
}

float Vec4::Magnitude() const
{
    return (float)sqrt(	MagSqr());
}

Vec4& Vec4::Modulate(const Vec4& _Val)
{
	x*=_Val.x;
	y*=_Val.y;
	z*=_Val.z;
	w*=_Val.w;
	return *this;
}


float	Vec4::MagSqr() const
{
	return (x*x) +	(y*y) + (z*z) + (w*w);
}

float	Vec4::Manhatten() const
{
	return (float)(fabs(x) + fabs(y) + fabs(z) + fabs(w));
}

Vec4	Vec4::LowVec(const Vec4& _A) const
{
	return Vec4(	UTIL_LOW(_A.x, x), 
					UTIL_LOW(_A.y, y), 
					UTIL_LOW(_A.z, z),
					UTIL_LOW(_A.w, w));
}

Vec4	Vec4::HighVec(const Vec4& _A) const
{
	return Vec4(	UTIL_HIGH(_A.x, x), 
					UTIL_HIGH(_A.y, y), 
					UTIL_HIGH(_A.z, z),
					UTIL_HIGH(_A.w, w));
}


Vec4 Vec4::Normalize() 
{
    float	fDistance = Magnitude();

    if (fDistance==0) 
	{
		// Error
		fDistance = 1.0f;
	}

	float	fInvD = 1.0f / fDistance;

	x *= fInvD;
    y *= fInvD;
    z *= fInvD;
	w *= fInvD;
	return *this;
}


int Vec4::Concurrent(const Vec4& _Vec) const
{
	return(x==_Vec.x && y==_Vec.y && z==_Vec.z && w==_Vec.w);
}



Vec4 operator+(const Vec4& vVec1,const Vec4&  vVec2) 
{
	return Vec4( vVec1.x + vVec2.x,
					vVec1.y + vVec2.y,
					vVec1.z + vVec2.z,
					vVec1.w + vVec2.w);
}

Vec4 operator-(const Vec4&  vVec1,const Vec4&  vVec2) 
{
	return Vec4(	vVec1.x - vVec2.x,
					vVec1.y - vVec2.y,
					vVec1.z - vVec2.z,
					vVec1.w - vVec2.w);

}

Vec4 operator-(const Vec4&  vVec)            
{
	return Vec4( -vVec.x, -vVec.y, -vVec.z, -vVec.w);
}

Vec4 operator*(const Vec4&  vVec1,float fScalar)   
{
	return Vec4( vVec1.x * fScalar,
					vVec1.y * fScalar,
					vVec1.z * fScalar,
					vVec1.w * fScalar);
}

Vec4 operator*(float fScalar, const Vec4&  vVec1)  
{
	return Vec4(	vVec1.x * fScalar,
					vVec1.y * fScalar,
					vVec1.z * fScalar,
					vVec1.w * fScalar);
}

Vec4 operator / (const Vec4&  vVec1, float fScalar)   
{
	float Div = (float)(1.0f / fScalar);
	return Vec4(	vVec1.x * Div,
					vVec1.y * Div,
					vVec1.z * Div,
					vVec1.w * Div);
}



//Dotprod
float  operator^(const Vec4&  V1,const Vec4&  V2) 
{
    return V1.x * V2.x + V1.y * V2.y + V1.z * V2.z + V1.w * V2.w;
}

Vec4& Vec4::operator+= ( const Vec4& _Vec) 
{
	x += _Vec.x;
	y += _Vec.y;
	z += _Vec.z;
	w += _Vec.w;
    return ( *this ) ;
}

Vec4& Vec4::operator-= ( const Vec4& _Vec) 
{
	x -= _Vec.x;
	y -= _Vec.y;
	z -= _Vec.z;
	w -= _Vec.w;
    return ( *this ) ;
}

Vec4& Vec4::operator*= ( const float& _f) 
{
	x *= _f;
	y *= _f;
	z *= _f;
	w *= _f;

    return ( *this ) ;
}


Vec4& Vec4::operator/= ( const float& _f) 
{
	float fInv = 1.0f / _f;
	x *= fInv;
	y *= fInv; 
	z *= fInv;
	w *= fInv;

    return ( *this ) ;
}

math::Vec4 LerpVec4(const math::Vec4& From, const math::Vec4& To, float t)
{
	if (t < 0.0f) t = 0.0f;
	if (t > 1.0f) t = 1.0f;

	Vec4	Delta = To - From;
	return From + (Delta*t);
}